home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / javax / swing / JTextField.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  20.5 KB  |  639 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)JTextField.java    1.57 98/08/28
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14. package javax.swing;
  15.  
  16. import java.awt.*;
  17. import java.awt.event.*;
  18. import javax.swing.text.*;
  19. import javax.swing.plaf.*;
  20. import javax.swing.event.*;
  21. import javax.accessibility.*;
  22.  
  23. import java.io.ObjectOutputStream;
  24. import java.io.ObjectInputStream;
  25. import java.io.IOException;
  26.  
  27. /**
  28.  * JTextField is a lightweight component that allows the editing 
  29.  * of a single line of text.  It is intended to be source-compatible
  30.  * with java.awt.TextField where it is reasonable to do so.  This
  31.  * component has capabilities not found in the java.awt.TextField 
  32.  * class.  The superclass should be consulted for additional capabilities.
  33.  * <p>
  34.  * JTextField has a method to establish the string used as the
  35.  * command string for the action event that gets fired.  The
  36.  * java.awt.TextField used the text of the field as the command
  37.  * string for the ActionEvent.  JTextField will use the command
  38.  * string set with the <code>setActionCommand</code> method if not null, 
  39.  * otherwise it will use the text of the field as a compatibility with 
  40.  * java.awt.TextField.
  41.  * <p>
  42.  * The method <code>setEchoChar</code> and <code>getEchoChar</code>
  43.  * are not provided directly to avoid a new implementation of a
  44.  * pluggable look-and-feel inadvertantly exposing password characters.
  45.  * To provide password-like services a seperate class JPasswordField
  46.  * extends JTextField to provide this service with an independantly
  47.  * pluggable look-and-feel.
  48.  * <p>
  49.  * The java.awt.TextField could be monitored for changes by adding
  50.  * a TextListener for TextEvent's.  In the JTextComponent based
  51.  * components, changes are broadcasted from the model via a
  52.  * DocumentEvent to DocumentListeners.  The DocumentEvent gives 
  53.  * the location of the change and the kind of change if desired.
  54.  * The code fragment might look something like:
  55.  * <pre><code>
  56.  *    DocumentListener myListener = ??;
  57.  *    JTextField myArea = ??;
  58.  *    myArea.getDocument().addDocumentListener(myListener);
  59.  * </code></pre>
  60.  * <p>
  61.  * The horizontal alignment of JTextField can be set to be left
  62.  * justified, centered, or right justified if the required size
  63.  * of the field text is smaller than the size allocated to it.
  64.  * This is determined by the <code>setHorizontalAlignment</code>
  65.  * and <code>getHorizontalAlignment</code> methods.  The default
  66.  * is to be left justified.
  67.  * <p>
  68.  * For the keyboard keys used by this component in the standard Look and
  69.  * Feel (L&F) renditions, see the
  70.  * <a href="doc-files/Key-Index.html#JTextField">JTextField</a> key assignments.
  71.  * <p>
  72.  * For compatibility with java.awt.TextField, the VK_ENTER key fires
  73.  * the ActionEvent to the registered ActionListeners.  However, awt
  74.  * didn't have default buttons like swing does.  If a text field has
  75.  * focus and the VK_ENTER key is pressed, it will fire the fields
  76.  * ActionEvent rather than activate the default button.  To disable
  77.  * the compatibility with awt for text fields, the following code
  78.  * fragment will remove the binding of VK_ENTER from the default keymap
  79.  * used by all JTextFields if that is desired.
  80.  * <pre><code>
  81.  
  82.   static {
  83.     JTextField f = new JTextField();
  84.     KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
  85.     Keymap map = f.getKeymap();
  86.     map.removeKeyStrokeBinding(enter);
  87.   }
  88.  
  89.  * </code></pre>
  90.  * <p>
  91.  * Customized fields can easily be created by extending the model and
  92.  * changing the default model provided.  For example, the following piece
  93.  * of code will create a field that holds only upper case characters.  It
  94.  * will work even if text is pasted into from the clipboard or it is altered via 
  95.  * programmatic changes.
  96.  * <pre><code>
  97.  
  98. public class UpperCaseField extends JTextField {
  99.  
  100.     public UpperCaseField(int cols) {
  101.     super(cols);
  102.     }
  103.  
  104.     protected Document createDefaultModel() {
  105.     return new UpperCaseDocument();
  106.     }
  107.  
  108.     static class UpperCaseDocument extends PlainDocument {
  109.  
  110.         public void insertString(int offs, String str, AttributeSet a) 
  111.         throws BadLocationException {
  112.  
  113.         if (str == null) {
  114.         return;
  115.         }
  116.         char[] upper = str.toCharArray();
  117.         for (int i = 0; i < upper.length; i++) {
  118.         upper[i] = Character.toUpperCase(upper[i]);
  119.         }
  120.         super.insertString(offs, new String(upper), a);
  121.     }
  122.     }
  123. }
  124.  
  125.  * </code></pre>
  126.  * <p>
  127.  * <strong>Warning:</strong>
  128.  * Serialized objects of this class will not be compatible with
  129.  * future Swing releases.  The current serialization support is appropriate
  130.  * for short term storage or RMI between applications running the same
  131.  * version of Swing.  A future release of Swing will provide support for
  132.  * long term persistence.
  133.  *
  134.  * @beaninfo
  135.  *   attribute: isContainer false
  136.  *
  137.  * @author  Timothy Prinzing
  138.  * @version 1.57 08/28/98
  139.  * @see #setActionCommand
  140.  * @see JPasswordField
  141.  */
  142. public class JTextField extends JTextComponent implements SwingConstants {
  143.  
  144.     /**
  145.      * Constructs a new TextField.  A default model is created, the initial
  146.      * string is null, and the number of columns is set to 0.
  147.      */
  148.     public JTextField() {
  149.         this(null, null, 0);
  150.     }
  151.  
  152.     /**
  153.      * Constructs a new TextField initialized with the specified text.
  154.      * A default model is created and the number of columns is 0.
  155.      *
  156.      * @param text the text to be displayed, or null
  157.      */
  158.     public JTextField(String text) {
  159.         this(null, text, 0);
  160.     }
  161.  
  162.     /**
  163.      * Constructs a new empty TextField with the specified number of columns.
  164.      * A default model is created and the initial string is set to null.
  165.      *
  166.      * @param columns  the number of columns to use to calculate 
  167.      *   the preferred width.  If columns is set to zero, the
  168.      *   preferred width will be whatever naturally results from
  169.      *   the component implementation.
  170.      */ 
  171.     public JTextField(int columns) {
  172.         this(null, null, columns);
  173.     }
  174.  
  175.     /**
  176.      * Constructs a new TextField initialized with the specified text
  177.      * and columns.  A default model is created.
  178.      *
  179.      * @param text the text to be displayed, or null
  180.      * @param columns  the number of columns to use to calculate 
  181.      *   the preferred width.  If columns is set to zero, the
  182.      *   preferred width will be whatever naturally results from
  183.      *   the component implementation.
  184.      */
  185.     public JTextField(String text, int columns) {
  186.         this(null, text, columns);
  187.     }
  188.  
  189.     /**
  190.      * Constructs a new JTextField that uses the given text storage
  191.      * model and the given number of columns.  This is the constructor
  192.      * through which the other constructors feed.  If the document is null,
  193.      * a default model is created.
  194.      *
  195.      * @param doc  the text storage to use.  If this is null, a default
  196.      *   will be provided by calling the createDefaultModel method.
  197.      * @param text  the initial string to display, or null
  198.      * @param columns  the number of columns to use to calculate 
  199.      *   the preferred width >= 0.  If columns is set to zero, the
  200.      *   preferred width will be whatever naturally results from
  201.      *   the component implementation.
  202.      * @exception IllegalArgumentException if columns < 0
  203.      */
  204.     public JTextField(Document doc, String text, int columns) {
  205.         if (columns < 0) {
  206.             throw new IllegalArgumentException("columns less than zero.");
  207.         }
  208.         visibility = new DefaultBoundedRangeModel();
  209.         visibility.addChangeListener(new ScrollRepainter());
  210.         this.columns = columns;
  211.         if (doc == null) {
  212.             doc = createDefaultModel();
  213.         }
  214.         setDocument(doc);
  215.         if (text != null) {
  216.             setText(text);
  217.         }
  218.     }
  219.  
  220.     /**
  221.      * Gets the class ID for a UI.
  222.      *
  223.      * @return the ID ("TextFieldUI")
  224.      * @see JComponent#getUIClassID
  225.      * @see UIDefaults#getUI
  226.      */
  227.     public String getUIClassID() {
  228.         return uiClassID;
  229.     }
  230.  
  231.     
  232.     /**
  233.      * Calls to revalidate that come from within the textfield itself will
  234.      * be handled by validating the textfield. 
  235.      * 
  236.      * @see JComponent#revalidate
  237.      * @see JComponent#isValidateRoot
  238.      */
  239.     public boolean isValidateRoot() {
  240.         return true;
  241.     }
  242.  
  243.  
  244.     /**
  245.      * Returns the horizontal alignment of the text.
  246.      * Valid keys: JTextField.LEFT (the default), JTextField.CENTER,
  247.      * JTextField.RIGHT.
  248.      *
  249.      * @return the alignment
  250.      */
  251.     public int getHorizontalAlignment() {
  252.         return horizontalAlignment;
  253.     }
  254.     
  255.     /**
  256.      * Sets the horizontal alignment of the text.
  257.      * Valid keys: JTextField.LEFT (the default), JTextField.CENTER,
  258.      * JTextField.RIGHT.  invalidate() and repaint() are called when the
  259.      * alignment is set, and a PropertyChange event ("horizontalAlignment")
  260.      * is fired.
  261.      *
  262.      * @param alignment the alignment
  263.      * @exception IllegalArgumentException if the alignment
  264.      *  specified is not a valid key.
  265.      * @beaninfo
  266.      *   preferred: true
  267.      *       bound: true
  268.      * description: Set the field alignment to LEFT (the default), CENTER, RIGHT
  269.      *        enum: LEFT JTextField.LEFT CENTER JTextField.CENTER RIGHT JTextField.RIGHT
  270.      */
  271.      public void setHorizontalAlignment(int alignment) {
  272.         if (alignment == horizontalAlignment) return;
  273.         int oldValue = horizontalAlignment;
  274.         if ((alignment == LEFT) || (alignment == CENTER) || (alignment == RIGHT)) {
  275.             horizontalAlignment = alignment;
  276.         } else {
  277.             throw new IllegalArgumentException("horizontalAlignment");
  278.         }
  279.         firePropertyChange("horizontalAlignment", oldValue, horizontalAlignment);       
  280.         invalidate();
  281.         repaint();
  282.     }
  283.  
  284.     /**
  285.      * Creates the default implementation of the model
  286.      * to be used at construction if one isn't explicitly 
  287.      * given.  An instance of PlainDocument is returned.
  288.      *
  289.      * @return the default model implementation
  290.      */
  291.     protected Document createDefaultModel() {
  292.         return new PlainDocument();
  293.     }
  294.  
  295.     /**
  296.      * Returns the number of columns in this TextField.
  297.      *
  298.      * @return the number of columns >= 0
  299.      */
  300.     public int getColumns() {
  301.         return columns;
  302.     }
  303.  
  304.     /**
  305.      * Sets the number of columns in this TextField, and then invalidate
  306.      * the layout.
  307.      *
  308.      * @param columns the number of columns >= 0
  309.      * @exception IllegalArgumentException if columns is less than 0
  310.      * @beaninfo
  311.      * description: the number of columns preferred for display
  312.      */
  313.     public void setColumns(int columns) {
  314.         int oldVal = this.columns;
  315.         if (columns < 0) {
  316.             throw new IllegalArgumentException("columns less than zero.");
  317.         }
  318.         if (columns != oldVal) {
  319.             this.columns = columns;
  320.             invalidate();
  321.         }
  322.     }
  323.  
  324.     /**
  325.      * Gets the column width.
  326.      * The meaning of what a column is can be considered a fairly weak
  327.      * notion for some fonts.  This method is used to define the width
  328.      * of a column.  By default this is defined to be the width of the
  329.      * character <em>m</em> for the font used.  This method can be 
  330.      * redefined to be some alternative amount
  331.      *
  332.      * @return the column width >= 1
  333.      */
  334.     protected int getColumnWidth() {
  335.         if (columnWidth == 0) {
  336.             FontMetrics metrics = getFontMetrics(getFont());
  337.             columnWidth = metrics.charWidth('m');
  338.         }
  339.         return columnWidth;
  340.     }
  341.  
  342.     /**
  343.      * Returns the preferred size Dimensions needed for this 
  344.      * TextField.  If a non-zero number of columns has been
  345.      * set, the width is set to the columns multiplied by
  346.      * the column width. 
  347.      *
  348.      * @return the dimensions
  349.      */
  350.     public Dimension getPreferredSize() {
  351.         synchronized (getTreeLock()) {
  352.             Dimension size = super.getPreferredSize();
  353.             if (columns != 0) {
  354.                 size.width = columns * getColumnWidth();
  355.             }
  356.             return size;
  357.         }
  358.     }
  359.  
  360.     /**
  361.      * Sets the current font.  This removes cached row height and column
  362.      * width so the new font will be reflected.  revalidate() is called
  363.      * after setting the font.
  364.      *
  365.      * @param f the new font
  366.      */
  367.     public void setFont(Font f) {
  368.         super.setFont(f);
  369.         columnWidth = 0;
  370.     }
  371.  
  372.     /**
  373.      * Adds the specified action listener to receive 
  374.      * action events from this textfield.
  375.      *
  376.      * @param l the action listener
  377.      */ 
  378.     public synchronized void addActionListener(ActionListener l) {
  379.         listenerList.add(ActionListener.class, l);
  380.     }
  381.  
  382.     /**
  383.      * Removes the specified action listener so that it no longer
  384.      * receives action events from this textfield.
  385.      *
  386.      * @param l the action listener 
  387.      */ 
  388.     public synchronized void removeActionListener(ActionListener l) {
  389.         listenerList.remove(ActionListener.class, l);
  390.     }
  391.  
  392.     /**
  393.      * Notifies all listeners that have registered interest for
  394.      * notification on this event type.  The event instance 
  395.      * is lazily created using the parameters passed into 
  396.      * the fire method.  The listener list is processed in last to
  397.      * first order.
  398.      * @see EventListenerList
  399.      */
  400.     protected void fireActionPerformed() {
  401.         // Guaranteed to return a non-null array
  402.         Object[] listeners = listenerList.getListenerList();
  403.         ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
  404.                                         (command != null) ? command : getText());
  405.         // Process the listeners last to first, notifying
  406.         // those that are interested in this event
  407.         for (int i = listeners.length-2; i>=0; i-=2) {
  408.             if (listeners[i]==ActionListener.class) {
  409.                 ((ActionListener)listeners[i+1]).actionPerformed(e);
  410.             }          
  411.         }
  412.     }
  413.  
  414.     /**
  415.      * Sets the command string used for action events.
  416.      *
  417.      * @param command the command string
  418.      */
  419.     public void setActionCommand(String command) {
  420.         this.command = command;
  421.     }
  422.  
  423.     /**
  424.      * Fetches the command list for the editor.  This is
  425.      * the list of commands supported by the plugged-in UI
  426.      * augmented by the collection of commands that the
  427.      * editor itself supports.  These are useful for binding
  428.      * to events, such as in a keymap.
  429.      *
  430.      * @return the command list
  431.      */
  432.     public Action[] getActions() {
  433.         return TextAction.augmentList(super.getActions(), defaultActions);
  434.     }
  435.  
  436.     /** 
  437.      * Processes action events occurring on this textfield by
  438.      * dispatching them to any registered ActionListener objects.
  439.      * This is normally called by the controller registered with
  440.      * textfield.
  441.      */  
  442.     public void postActionEvent() {
  443.         fireActionPerformed();
  444.     }
  445.  
  446.     // --- Scrolling support -----------------------------------
  447.  
  448.     /**
  449.      * Gets the visibility of the text field.  This can
  450.      * be adjusted to change the location of the visible
  451.      * area if the size of the field is greater than
  452.      * the area that was allocated to the field.
  453.      *
  454.      * The fields look-and-feel implementation manages
  455.      * the values of the minimum, maximum, and extent
  456.      * properties on the BoundedRangeModel.
  457.      * 
  458.      * @return the visibility
  459.      * @see BoundedRangeModel
  460.      */
  461.     public BoundedRangeModel getHorizontalVisibility() {
  462.         return visibility;
  463.     }
  464.  
  465.     /**
  466.      * Gets the scroll offset.
  467.      *
  468.      * @return the offset >= 0
  469.      */
  470.     public int getScrollOffset() {
  471.         return visibility.getValue();
  472.     }
  473.  
  474.     /**
  475.      * Sets the scroll offset.
  476.      *
  477.      * @param scrollOffset the offset >= 0
  478.      */
  479.     public void setScrollOffset(int scrollOffset) {
  480.         visibility.setValue(scrollOffset);
  481.     }
  482.     
  483.     /**
  484.      * Scrolls the field left or right.
  485.      *
  486.      * @param r the region to scroll
  487.      */
  488.     public void scrollRectToVisible(Rectangle r) {
  489.         // convert to coordinate system of the bounded range
  490.         int x = r.x + visibility.getValue();
  491.         if (x < visibility.getValue()) {
  492.             // Scroll to the left
  493.             visibility.setValue(x - 2);
  494.         } else if(x > visibility.getValue() + visibility.getExtent()) {
  495.             // Scroll to the right
  496.             visibility.setValue(x - visibility.getExtent() + 2);
  497.         }
  498.     }
  499.  
  500.     // --- variables -------------------------------------------
  501.  
  502.     /**
  503.      * Name of the action to send notification that the
  504.      * contents of the field have been accepted.  Typically
  505.      * this is bound to a carriage-return.
  506.      */
  507.     public static final String notifyAction = "notify-field-accept";
  508.  
  509.     private BoundedRangeModel visibility;
  510.     private int horizontalAlignment  = LEFT;
  511.     private int columns;
  512.     private int columnWidth;
  513.     private String command;
  514.  
  515.     private static final Action[] defaultActions = {
  516.         new NotifyAction()
  517.     };
  518.  
  519.     /**
  520.      * @see #getUIClassID
  521.      * @see #readObject
  522.      */
  523.     private static final String uiClassID = "TextFieldUI";
  524.  
  525.     // --- Action implementations -----------------------------------
  526.  
  527.     static class NotifyAction extends TextAction {
  528.  
  529.         NotifyAction() {
  530.             super(notifyAction);
  531.         }
  532.  
  533.         public void actionPerformed(ActionEvent e) {
  534.             JTextComponent target = getFocusedComponent();
  535.             if (target instanceof JTextField) {
  536.                 JTextField field = (JTextField) target;
  537.                 field.postActionEvent();
  538.             }
  539.         }
  540.     }
  541.  
  542.     class ScrollRepainter implements ChangeListener {
  543.  
  544.         public void stateChanged(ChangeEvent e) {
  545.             repaint();
  546.         }
  547.  
  548.     }
  549.  
  550.  
  551.     /** 
  552.      * See readObject() and writeObject() in JComponent for more 
  553.      * information about serialization in Swing.
  554.      */
  555.     private void writeObject(ObjectOutputStream s) throws IOException {
  556.         s.defaultWriteObject();
  557.     if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  558.         ui.installUI(this);
  559.     }
  560.     }
  561.  
  562.  
  563.     /**
  564.      * Returns a string representation of this JTextField. This method 
  565.      * is intended to be used only for debugging purposes, and the 
  566.      * content and format of the returned string may vary between      
  567.      * implementations. The returned string may be empty but may not 
  568.      * be <code>null</code>.
  569.      * <P>
  570.      * Overriding paramString() to provide information about the
  571.      * specific new aspects of the JFC components.
  572.      * 
  573.      * @return  a string representation of this JTextField.
  574.      */
  575.     protected String paramString() {
  576.         String horizontalAlignmentString;
  577.         if (horizontalAlignment == LEFT) {
  578.         horizontalAlignmentString = "LEFT";
  579.     } else if (horizontalAlignment == CENTER) {
  580.         horizontalAlignmentString = "CENTER";
  581.     } else if (horizontalAlignment == RIGHT) {
  582.         horizontalAlignmentString = "RIGHT";
  583.     } else horizontalAlignmentString = "";
  584.         String commandString = (command != null ?
  585.                 command : "");
  586.  
  587.         return super.paramString() +
  588.         ",columns=" + columns +
  589.         ",columnWidth=" + columnWidth +
  590.         ",command=" + commandString +
  591.         ",horizontalAlignment=" + horizontalAlignmentString;
  592.     }
  593.  
  594.  
  595. /////////////////
  596. // Accessibility support
  597. ////////////////
  598.  
  599.  
  600.     /**
  601.      * Get the AccessibleContext associated with this JTextField.
  602.      * Creates a new context if necessary.
  603.      *
  604.      * @return the AccessibleContext of this JTextField
  605.      */
  606.     public AccessibleContext getAccessibleContext() {
  607.         if (accessibleContext == null) {
  608.             accessibleContext = new AccessibleJTextField();
  609.         }
  610.         return accessibleContext;
  611.     }
  612.  
  613.     /**
  614.      * The class used to obtain the accessible role for this object.
  615.      * <p>
  616.      * <strong>Warning:</strong>
  617.      * Serialized objects of this class will not be compatible with
  618.      * future Swing releases.  The current serialization support is appropriate
  619.      * for short term storage or RMI between applications running the same
  620.      * version of Swing.  A future release of Swing will provide support for
  621.      * long term persistence.
  622.      */
  623.     protected class AccessibleJTextField extends AccessibleJTextComponent {
  624.  
  625.         /**
  626.          * Gets the state set of this object.
  627.          *
  628.          * @return an instance of AccessibleStateSet describing the states 
  629.          * of the object
  630.          * @see AccessibleState
  631.          */
  632.         public AccessibleStateSet getAccessibleStateSet() {
  633.             AccessibleStateSet states = super.getAccessibleStateSet();
  634.             states.add(AccessibleState.SINGLE_LINE);
  635.             return states;
  636.         }
  637.     }
  638. }
  639.